package shared.server

import shared.file._
import java.net._
import java.io._
import java.util.concurrent._
import shared.file.FileTransferCollection

object FileServer {
  val defaultPort = 8999
  
  def open(host: InetAddress, port: Int) = {
    new ServerSocket(port, 0, host)
  }
}

class FileServer(val host: InetAddress, val port: Int, val fs: Filesystem, val queue: FileTransferCollection) extends IOAware {
  def this(files: Filesystem, q: FileTransferCollection) = this(InetAddress.getLocalHost, FileServer.defaultPort, files, q)
  
  if(this.fs == null) {
    error("filesystem == null")
  }
  
  private val ss = FileServer.open(host, port)
  private val threadPool = Executors.newFixedThreadPool(10, new ThreadFactory{
    override def newThread(r: Runnable) = {
      val t = new Thread(r)
      t.setDaemon(true)
      t
    }
})
  
  def handle(s: Socket) = {
    
    
    threadPool.submit( new Runnable { def run = {
      try {
        println("handling: " + s.getRemoteSocketAddress)
        val in = new BufferedReader(new InputStreamReader(s.getInputStream, "UTF-8"))
        val file = in.readLine
        println("file selected: " + file)
        val selected = fs.getFile(file)
        println("to transfer: " + selected)
        
        if(selected.isDefined) {
          println("transfering file: " + file)
          val ft = queue.add(file, selected.get.size)
          val out = s.getOutputStream
          eachChunk (selected.get.open) { (data, len)  =>
            ft.add(len)
            out.write(data, 0, len)
          }
        } else {
          println("file not found: " + file)
          }
        } catch {
          case e: Exception => e.printStackTrace
      } finally {
        s.close
      }                                        
    } })
  }
  
  def report(e: IOException) = {
    e.printStackTrace
  }
  
  def start() = {
    val task = new Runnable {
      def run = {
        def loop(k: Boolean, ss: ServerSocket): Unit = {
          if(k) {
            try {
              handle(ss.accept)
            } catch {
              case e:IOException => {
                if(!ss.isClosed) {
                  report(e)
                } else {
                  loop(false, ss)
                }		
              }	
            }	
            loop(true, ss)
          }
        }
        loop(true, ss)
      }
    }
    
    val thread = new Thread(task, "socket-acceptor")
    thread.setDaemon(true)
    thread.start
  }
  
  def stop = ss.close
  
  
}
